
#import "MyEncrypt.h"
@import Foundation;
@import CommonCrypto;



static const char _a[64] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+/";
static const short _b[256] = {
    -2, -2, -2, -2, -2, -2, -2, -2, -2, -1, -1, -2, -1, -1, -2, -2,
    -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2,
    -1, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, 62, -2, -2, -2, 63,
    52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -2, -2, -2, -2, -2, -2,
    -2,  26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
    41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -2, -2, -2, -2, -2,
    -2, 0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14,
    15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -2, -2, -2, -2, -2,
    -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2,
    -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2,
    -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2,
    -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2,
    -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2,
    -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2,
    -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2,
    -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2
};
@implementation MyEncrypt
+ (NSString*)getmd5WithString:(NSString *)string
{
    const char* original_str=[string UTF8String];
    unsigned char digist[CC_MD5_DIGEST_LENGTH]; //CC_MD5_DIGEST_LENGTH = 16
    CC_MD5(original_str, (uint)strlen(original_str), digist);
    NSMutableString* outPutStr = [NSMutableString stringWithCapacity:10];
    for(int  i =0; i<CC_MD5_DIGEST_LENGTH;i++){
        [outPutStr appendFormat:@"%02x", digist[i]];//小写x表示输出的是小写MD5，大写X表示输出的是大写MD5
    }
    return [outPutStr lowercaseString];
} 
+ (NSString *)encryptString:(NSString *)strData seed:(NSString *)seed{
    NSMutableData * rawData = [strData dataUsingEncoding:NSUTF8StringEncoding].mutableCopy;
    NSData * vData = [[MyEncrypt getmd5WithString:seed] dataUsingEncoding:NSUTF8StringEncoding];
    const UInt8 * rawP = [rawData bytes];
    const UInt8 * vP = [vData bytes];
    for (NSInteger i = 0; i < [rawData length]; i++) {
        UInt8 rawVal = *(rawP + i);
        UInt8 addVal = *(vP + i % [vData length]);
        UInt8 newVal = rawVal + addVal;
        [rawData replaceBytesInRange:NSMakeRange(i, 1) withBytes:&newVal];
    }
    return [MyEncrypt encryptData:rawData];
}
+ (NSString *)encryptData:(NSData *)objData {
    const unsigned char * objRawData = [objData bytes];
    
    char * strResult;
    unsigned long intLength = [objData length];
    if (intLength == 0) return nil;
    NSMutableArray<NSNumber *> * charsArr = [NSMutableArray arrayWithCapacity:((intLength + 2) / 3) * 4];
    NSInteger idx = 0;
    strResult = (char *)malloc(((intLength + 2) / 3) * 4 * sizeof(char));
    
    while(intLength > 2) {
        charsArr[idx] = [NSNumber numberWithChar:_a[objRawData[0] >> 2]];
        idx++;
        
        charsArr[idx] = [NSNumber numberWithChar:_a[((objRawData[0] & 0x03) << 4) + (objRawData[1] >> 4)]];
        idx++;
        charsArr[idx] = [NSNumber numberWithChar:_a[((objRawData[1] & 0x0f) << 2) + (objRawData[2] >> 6)]];
        idx++;
        charsArr[idx] = [NSNumber numberWithChar:_a[objRawData[2] & 0x3f]];
        idx++;
        
        objRawData += 3;
        intLength -= 3;
    }
    
    if (intLength != 0) {
        charsArr[idx] = [NSNumber numberWithChar:_a[objRawData[0] >> 2]];
        idx++;
        if (intLength > 1) {
            charsArr[idx] = [NSNumber numberWithChar:_a[((objRawData[0] & 0x03) << 4) + (objRawData[1] >> 4)]];
            idx++;
            charsArr[idx] = [NSNumber numberWithChar:_a[(objRawData[1] & 0x0f) << 2]];
            idx++;
            charsArr[idx] = [NSNumber numberWithChar:'='];
            idx++;
        } else {
            charsArr[idx] = [NSNumber numberWithChar:_a[(objRawData[0] & 0x03) << 4]];
            idx++;
            charsArr[idx] = [NSNumber numberWithChar:'='];
            idx++;
            charsArr[idx] = [NSNumber numberWithChar:'='];
            idx++;
        }
    }
    NSMutableString * rs = @"".mutableCopy;
    for (NSNumber * charNum in charsArr) {
        char c = charNum.charValue;
        char cs[2] = {c,'\0'};
        char * cp = cs;
        NSString * css = [[NSString alloc]initWithCString:cp encoding:NSASCIIStringEncoding];
        [rs appendString:css];
    }
    return rs;
}


+ (NSString *)decryptString:(NSString *)encryptedString seed:(NSString *)seed{
    const char* objPointer = [encryptedString cStringUsingEncoding:NSASCIIStringEncoding];
    unsigned long intLength = strlen(objPointer);
    int intCurrent;
    int i = 0, j = 0, k;
    
    unsigned char * objResult;
    objResult = calloc(intLength, sizeof(char));
    
    while ( ((intCurrent = *objPointer++) != '\0') && (intLength-- > 0) ) {
        if (intCurrent == '=') {
            if (*objPointer != '=' && ((i % 4) == 1)) {// || (intLength > 0)) {
                free(objResult);
                return nil;
            }
            continue;
        }
        
        intCurrent = _b[intCurrent];
        if (intCurrent == -1) {
            continue;
        } else if (intCurrent == -2) {
            free(objResult);
            return nil;
        }
        
        switch (i % 4) {
            case 0:
                objResult[j] = intCurrent << 2;
                break;
                
            case 1:
                objResult[j++] |= intCurrent >> 4;
                objResult[j] = (intCurrent & 0x0f) << 4;
                break;
                
            case 2:
                objResult[j++] |= intCurrent >>2;
                objResult[j] = (intCurrent & 0x03) << 6;
                break;
                
            case 3:
                objResult[j++] |= intCurrent;
                break;
        }
        i++;
    }
    
    k = j;
    if (intCurrent == '=') {
        switch (i % 4) {
            case 1:
                free(objResult);
                return nil;
            case 2:
                k++;
            case 3:
                objResult[k] = 0;
        }
    }
    
    NSMutableData * rawData = [[NSMutableData alloc] initWithBytes:objResult length:j] ;
    NSData * vData = [[MyEncrypt getmd5WithString:seed] dataUsingEncoding:NSUTF8StringEncoding];
    const UInt8 * rawP = [rawData bytes];
    const UInt8 * vP = [vData bytes];
    for (NSInteger i = 0; i < [rawData length]; i++) {
        UInt8 rawVal = *(rawP + i);
        UInt8 minVal = *(vP + i % [vData length]);
        UInt8 newVal = rawVal - minVal;
        [rawData replaceBytesInRange:NSMakeRange(i, 1) withBytes:&newVal];
    }
    free(objResult);
    return [[NSString alloc]initWithData:rawData encoding:NSUTF8StringEncoding];
}

//MARK: - AES
+ (NSString *)aesDecryptStringWithString:(NSString *)string andKey:(NSString *)key

{
    
    NSMutableData *data = [NSMutableData dataWithCapacity:string.length/2.0];
    
    unsigned char whole_bytes;
    
    char byte_chars[3] = {'\0','\0','\0'};
    
    int i;
    
    for(i = 0 ; i < [string length]/2 ; i++)
        
    {
        
        byte_chars[0] = [string characterAtIndex:i * 2];
        
        byte_chars[1] = [string characterAtIndex:i * 2 + 1];
        
        whole_bytes = strtol(byte_chars, NULL, 16);
        
        [data appendBytes:&whole_bytes length:1];
        
    }
    
    NSData *result = [self aesDecryptDataWithData:data andKey:key];
    
    if(result && result.length > 0)
        
    {
        
        return [[NSString alloc] initWithData:result encoding:NSUTF8StringEncoding];
        
    }
    
    return nil;
    
}
// 解密
+ (NSData *)aesEncryptDataWithData:(NSData *)data Key:(NSString *)key

{
    
    char keyPtr[kCCKeySizeAES128 + 1];
    
    bzero(keyPtr, sizeof(keyPtr));
    
    [key getCString:keyPtr maxLength:sizeof(key) encoding:NSUTF8StringEncoding];
    
    NSUInteger dataLength = [data length];
    
    size_t bufferSize = dataLength + kCCBlockSizeAES128;
    
    void *buffer = malloc(bufferSize);
    
    size_t numBytesEncrypted = 0;
    
    CCCryptorStatus cryptStatus = CCCrypt(kCCEncrypt,
                                          
                                          kCCAlgorithmAES128,
                                          
                                          kCCOptionPKCS7Padding | kCCOptionECBMode,
                                          
                                          keyPtr,
                                          
                                          kCCBlockSizeAES128,
                                          
                                          NULL,
                                          
                                          [data bytes],
                                          
                                          dataLength,
                                          
                                          buffer,
                                          
                                          bufferSize,
                                          
                                          &numBytesEncrypted);
    
    if(cryptStatus == kCCSuccess)
        
    {
        
        return [NSData dataWithBytesNoCopy:buffer length:numBytesEncrypted];
        
    }
    
    free(buffer);
    
    return nil;
    
}

+ (NSData *)aesDecryptDataWithData:(NSData *)data andKey:(NSString *)key

{
    
    char keyPtr[kCCKeySizeAES128 + 1];
    
    bzero(keyPtr, sizeof(keyPtr));
    
    [key getCString:keyPtr maxLength:sizeof(keyPtr) encoding:NSUTF8StringEncoding];
    
    NSUInteger dataLength = [data length];
    
    size_t bufferSize = dataLength + kCCBlockSizeAES128;
    
    void *buffer = malloc(bufferSize);
    
    size_t numBytesDecrypted = 0;
    
    CCCryptorStatus cryptStatus = CCCrypt(kCCDecrypt, kCCAlgorithmAES128, kCCOptionPKCS7Padding | kCCOptionECBMode, keyPtr, kCCBlockSizeAES128, NULL, [data bytes], dataLength, buffer, bufferSize, &numBytesDecrypted);
    
    if(cryptStatus == kCCSuccess)
        
    {
        
        return [NSData dataWithBytesNoCopy:buffer length:numBytesDecrypted];
        
    }
    
    free(buffer);
    
    return nil;
    
}

+ (NSString *)aesEncryptStringWithString:(NSString *)string andKey:(NSString *)key

{
    
    const char *cStr = [string cStringUsingEncoding:NSUTF8StringEncoding];
    
    NSData *data = [NSData dataWithBytes:cStr length:[string length]];
    
    //对数据进行加密
    
    NSData *result = [self aesEncryptDataWithData:data Key:key];
    
    //转换为2进制字符串
    
    if(result && result.length > 0)
        
    {
        
        Byte *datas = (Byte *)[result bytes];
        
        NSMutableString *outPut = [NSMutableString stringWithCapacity:result.length];
        
        for(int i = 0 ; i < result.length ; i++)
            
        {
            
            [outPut appendFormat:@"%02x",datas[i]];
            
        }
        
        return outPut;
        
    }
    
    return nil;
    
}

@end
